module Y86_Controller(CLOCK, reset, hold, id, fetch_addr, fetch_data_i, fetch_ub, fetch_lb, mem_addr, mem_enable, mem_data_i, mem_data_o, mem_ub, mem_lb, mem_write, lock, debug, CC_debug);

input CLOCK;
input reset;
input hold;

input id;

input [15:0] fetch_data_i;
input [15:0] mem_data_i;

output [31:0] fetch_addr;
output fetch_lb;
output fetch_ub;
output [31:0]mem_addr;
output mem_enable;
output [15:0] mem_data_o;
output mem_ub;
output mem_lb;
output mem_write;
output [31:0] debug;
output [3:0] CC_debug;
output lock;

wire hold_f;
wire [3:0] icode_f;
wire [3:0] ifun_f;
wire [3:0] rA_f;
wire [3:0] rB_f;
wire [31:0] valC_f;
wire [31:0] valP_f;
wire WAIT_f;

wire [3:0] icode_d;
wire [3:0] ifun_d;
wire [3:0] rA_d;
wire [3:0] rB_d;
wire [31:0] valC_d;
wire [31:0] valP_d;
wire [31:0] valA_d;
wire [31:0] valB_d;
wire [3:0] dstE_d;
wire [3:0] dstM_d;
wire WAIT_d;
wire [31:0] regA;
wire [31:0] regB;

wire [3:0] icode_e;
wire [3:0] ifun_e;
wire [3:0] rA_e;
wire [3:0] rB_e;
wire [31:0] valC_e;
wire [31:0] valP_e;
wire [31:0] valA_e;
wire [31:0] valB_e;
wire [31:0] CC_e;
wire [3:0] dstE_e;
wire [3:0] dstM_e;
wire [31:0] valE_e;
wire [31:0] valM_e;
wire [3:0] srcA;
wire [3:0] srcB;

wire [3:0] icode_m;
wire [3:0] ifun_m;
wire [3:0] rA_m;
wire [3:0] rB_m;
wire [31:0] valC_m;
wire [31:0] valP_m;
wire [31:0] valA_m;
wire [31:0] valB_m;
wire [3:0] dstE_m;
wire [3:0] dstM_m;
wire [31:0] valE_m;
wire [31:0] valM_m;
wire WAIT_m;


wire [3:0] icode_w;
wire [3:0] dstE_w;
wire [3:0] dstM_w;
wire [31:0] valE_w;
wire [31:0] valM_w;
 
wire [31:0]CC;
wire [31:0]CC_in;

assign CC_in = (!reset)? {3'b000, id, 28'h0000000}: CC_e;


Register CC_Reg (
				.clk(CLOCK), 
				.in(CC_in), 
				.out(CC));
				
assign fetch_lb = 1;
assign fetch_ub = 1;	
			
FETCH fet(
				.clk(CLOCK),
				.reset(reset),
				.hold(WAIT_d | mem_enable | hold), 
				.icode_d(icode_d),
				.icode_e(icode_e),
				.icode_m(icode_w),
				.mem_addr(fetch_addr),
				.valM(valM_w),
				.CC(CC_in),
				.mem_data(fetch_data_i),
				.icode(icode_f),
				.ifun(ifun_f),
				.rA(rA_f),
				.rB(rB_f),
				.valC(valC_f),
				.valP(valP_f),
				.WAIT(WAIT_f),
				.lock(lock));

StageRegisters if_id(
				.clk(CLOCK),
				.hold(WAIT_d | WAIT_m | hold), 
				.nop(WAIT_f),
				.reset(reset),
				.icode_i(icode_f),
				.ifun_i(ifun_f),
				.rA_i(rA_f),
				.rB_i(rB_f),
				.valC_i(valC_f),
				.valP_i(valP_f),
				.icode_o(icode_d),
				.ifun_o(ifun_d),
				.rA_o(rA_d),
				.rB_o(rB_d),
				.valC_o(valC_d),
				.valP_o(valP_d));	
DECODE dec(
				.icode(icode_d), 
				.rA(rA_d), 
				.rB(rB_d),
				.CC(CC_e),
				.dstE_e(dstE_e),
				.dstM_e(dstM_e),
				.dstE_m(dstE_m),
				.dstM_m(dstM_m),
				.dstE_w(dstE_w),
				.dstM_w(dstM_w),
				.valE_e(valE_e),
				.valM_e(valM_e),
				.valE_m(valE_m),
				.valM_m(valM_m),
				.valE_w(valE_w),
				.valM_w(valM_w),
				.regA(regA),
				.regB(regB),
				.valA(valA_d),
				.valB(valB_d),
				.dstE(dstE_d),
				.dstM(dstM_d),
				.srcA(srcA),	
				.srcB(srcB),
				.WAIT(WAIT_d));	
			
RegBank regbank(
				.clk(CLOCK), 
				.srcA(srcA), 
				.srcB(srcB),
				.dstE(dstE_w), 
				.valE(valE_w), 
				.dstM(dstM_w), 
				.valM(valM_w), 
				.valA(regA), 
				.valB(regB), 
				.reset(reset));

StageRegisters id_ex(
				.clk(CLOCK),
				.nop(WAIT_d), 
				.hold(WAIT_m | hold),
				.reset(reset),
				.icode_i(icode_d),
				.ifun_i(ifun_d),
				.rA_i(rA_d),
				.rB_i(rB_d),
				.dstE_i(dstE_d),
				.dstM_i(dstM_d),
				.valC_i(valC_d),
				.valP_i(valP_d),
				.valA_i(valA_d),
				.valB_i(valB_d),
				.icode_o(icode_e),
				.ifun_o(ifun_e),
				.rA_o(rA_e),
				.rB_o(rB_e),
				.dstE_o(dstE_e),
				.dstM_o(dstM_e),
				.valC_o(valC_e),
				.valP_o(valP_e),
				.valA_o(valA_e),
				.valB_o(valB_e)
				);
					
EXECUTE exec(
				.icode(icode_e), 
				.ifun(ifun_e),
				.icode_m(icode_m),
				.dstM_m(dstM_m),
				.valM(valM_m),
				.valC(valC_e), 
				.valA(valA_e), 
				.valB(valB_e), 
				.CC_i(CC), 
				.valE(valE_e), 
				.CC_o(CC_e));
			 

StageRegisters ex_mem(
				.clk(CLOCK),
				.nop(1'b0), 
				.hold(WAIT_m | hold),
				.reset(reset),
				.icode_i(icode_e),
				.ifun_i(ifun_e),
				.rA_i(rA_e),
				.rB_i(rB_e),
				.dstE_i(dstE_e),
				.dstM_i(dstM_e),
				.valC_i(valC_e),
				.valP_i(valP_e),
				.valA_i(valA_e),
				.valB_i(valB_e),
				.valE_i(valE_e),
				.icode_o(icode_m),
				.ifun_o(ifun_m),
				.rA_o(rA_m),
				.rB_o(rB_m),
				.dstE_o(dstE_m),
				.dstM_o(dstM_m),
				.valC_o(valC_m),
				.valP_o(valP_m),
				.valA_o(valA_m),
				.valB_o(valB_m),
				.valE_o(valE_m));

				
MEM m(
				.clk(CLOCK),
				.reset(reset),
				.hold(hold),
				.icode(icode_m),
				.valA(valA_m),
				.valE(valE_m),
				.valP(valP_m),
				.mem_data_i(mem_data_i),
				.mem_address(mem_addr),
				.mem_data_o(mem_data_o),
				.mem_ub(mem_ub),
				.mem_lb(mem_lb),
				.mem_access(mem_enable),
				.mem_write(mem_write),
				.valM(valM_m),
				.WAIT(WAIT_m));
				
				
StageRegisters mem_wb(
				.clk(CLOCK),
				.reset(reset),
				.nop(WAIT_m), 
				.hold(hold),
				.icode_i(icode_m),
				.dstE_i(dstE_m),
				.dstM_i(dstM_m),
				.valE_i(valE_m),
				.valM_i(valM_m),
				.icode_o(icode_w),
				.dstE_o(dstE_w),
				.dstM_o(dstM_w),
				.valE_o(valE_w),
				.valM_o(valM_w)
				);
			 
/*assign byte1_o = {icode_d[3:0], ifun_d[3:0]};
assign byte2_o = {icode_f[3:0], ifun_f[3:0]};
assign byte3_o = valE_e[7:0];

assign WAIT = WAIT_f;*/

assign debug = {icode_f[3:0], icode_d[3:0],icode_e[3:0],icode_m[3:0],valB_d[31:16]};
assign CC_debug = {CC[31], CC[30], CC[29], CC[28]};

endmodule